This repository has no description
4.6 kB
158 lines
1"use client";
2
3import { useEffect, useState } from "react";
4import { useRouter, useParams } from "next/navigation";
5import { getAccessToken } from "@/services/auth";
6import { ApiClient } from "@/api-client/ApiClient";
7import { UrlCard } from "@/components/UrlCard";
8import type { GetCollectionPageResponse } from "@/api-client/types";
9import {
10 Button,
11 Group,
12 Loader,
13 Stack,
14 Text,
15 Card,
16 Title,
17 Box,
18 SimpleGrid,
19} from "@mantine/core";
20
21export default function CollectionPage() {
22 const [collection, setCollection] =
23 useState<GetCollectionPageResponse | null>(null);
24 const [loading, setLoading] = useState(true);
25 const [error, setError] = useState("");
26 const router = useRouter();
27 const params = useParams();
28 const collectionId = params.collectionId as string;
29
30 // Create API client instance
31 const apiClient = new ApiClient(
32 process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:3000",
33 () => getAccessToken(),
34 );
35
36 useEffect(() => {
37 const fetchCollection = async () => {
38 try {
39 setLoading(true);
40 const response = await apiClient.getCollectionPage(collectionId, {
41 limit: 50,
42 });
43 setCollection(response);
44 } catch (error: any) {
45 console.error("Error fetching collection:", error);
46 setError(error.message || "Failed to load collection");
47 } finally {
48 setLoading(false);
49 }
50 };
51
52 if (collectionId) {
53 fetchCollection();
54 }
55 }, [collectionId]);
56
57 if (loading) {
58 return <Loader />;
59 }
60
61 if (error || !collection) {
62 return (
63 <Stack align="center">
64 <Text c={"red"}>{error || "Collection not found"}</Text>
65 <Button onClick={() => router.back()}>Go Back</Button>
66 </Stack>
67 );
68 }
69
70 return (
71 <Box>
72 <Stack>
73 <Group justify="space-between">
74 <Button variant="outline" onClick={() => router.back()}>
75 ← Back
76 </Button>
77 <Group>
78 <Button
79 variant="outline"
80 onClick={() => router.push(`/collections/${collectionId}/edit`)}
81 >
82 Edit Collection
83 </Button>
84 <Button onClick={() => router.push("/cards/add")}>Add Card</Button>
85 </Group>
86 </Group>
87
88 {/* Collection Header */}
89 <Card withBorder>
90 <Stack>
91 <Text fw={600} lineClamp={1}>
92 {collection.name}
93 </Text>
94 {collection.description && (
95 <Text lineClamp={2}>{collection.description}</Text>
96 )}
97 </Stack>
98
99 <Group>
100 <Text fz={"sm"} c={"gray"}>
101 {collection.urlCards.length} cards
102 </Text>
103 <Text fz={"sm"} c={"gray"}>
104 By {collection.author.name} (@{collection.author.handle})
105 </Text>
106 </Group>
107 </Card>
108
109 {/* Cards Section */}
110 <Stack>
111 <Group justify="space-between">
112 <Title order={2}>Cards</Title>
113 {collection.pagination && collection.pagination.totalCount > 0 && (
114 <Text fz={"sm"} c={"gray"}>
115 Showing {collection.urlCards.length} of{" "}
116 {collection.pagination.totalCount} cards
117 </Text>
118 )}
119 </Group>
120
121 {collection.urlCards.length > 0 ? (
122 <Box>
123 <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing={"md"}>
124 {collection.urlCards.map((card) => (
125 <UrlCard
126 key={card.id}
127 cardId={card.id}
128 url={card.url}
129 title={card.cardContent.title}
130 description={card.cardContent.description}
131 author={card.cardContent.author}
132 imageUrl={card.cardContent.thumbnailUrl}
133 addedAt={card.createdAt}
134 note={card.note?.text}
135 />
136 ))}
137 </SimpleGrid>
138
139 {/* Pagination */}
140 {collection.pagination && collection.pagination.hasMore && (
141 <Stack align="center">
142 <Button variant="outline">Load More Cards</Button>
143 </Stack>
144 )}
145 </Box>
146 ) : (
147 <Stack align="center">
148 <Text c={"gray"}>No cards in this collection yet</Text>
149 <Button onClick={() => router.push("/cards/add")}>
150 Add Your First Card
151 </Button>
152 </Stack>
153 )}
154 </Stack>
155 </Stack>
156 </Box>
157 );
158}